// 引入 colored 库以支持颜色输出
use chrono::DateTime;
use colored::*;
use std::fs::{self, DirEntry, Metadata};
use std::time::{SystemTime, UNIX_EPOCH};

pub fn execute(args: &[String]) {
    // 解析命令行参数
    let mut show_hidden = false; // 是否显示隐藏文件
    let mut long_format = false; // 是否使用长格式显示
    let mut target_path = ".";   // 目标路径，默认为当前目录

    // 处理参数
    for arg in args {
        match arg.as_str() {
            "-a" => show_hidden = true, // 显示隐藏文件
            "-l" => long_format = true, // 长格式显示
            // 支持 -al 参数
            "-al" | "-la" => {
                show_hidden = true;
                long_format = true;
            }
            path => target_path = path, // 指定的目录路径
        }
    }

    // 读取指定目录的内容
    let entries = match fs::read_dir(target_path) {
        Ok(entries) => entries,
        Err(e) => {
            eprintln!("无法读取目录 {}: {}", target_path, e);
            return;
        }
    };

    // 分别收集目录和文件
    let mut directories = vec![];
    let mut files = vec![];

    for entry in entries {
        let entry = match entry {
            Ok(entry) => entry,
            Err(e) => {
                eprintln!("读取目录项时出错: {}", e);
                continue;
            }
        };

        let file_name = entry.file_name();
        let file_name_str = file_name.to_string_lossy();

        // 过滤隐藏文件
        if !show_hidden && file_name_str.starts_with('.') {
            continue;
        }

        // 根据文件类型分别放入目录和文件的集合
        if entry.file_type().map(|ft| ft.is_dir()).unwrap_or(false) {
            directories.push(entry);
        } else {
            files.push(entry);
        }
    }

    // 先输出目录，再输出文件
    for dir in &directories {
        output_entry(dir, long_format);
    }
    for file in &files {
        output_entry(file, long_format);
    }
}
// 输出单个文件或目录的信息
fn output_entry(entry: &fs::DirEntry, long_format: bool) {
    let file_name = entry.file_name();
    let file_name_str = file_name.to_string_lossy();

    if long_format {
        // 获取文件的详细信息
        if let Ok(metadata) = entry.metadata() {
            print_long_format(&metadata, &file_name_str);
        } else {
            eprintln!("无法获取 {} 的文件元数据", file_name_str);
        }
    } else {
        // 简单输出文件名，目录高亮显示
        if entry.file_type().map(|ft| ft.is_dir()).unwrap_or(false) {
            println!("{}", file_name_str.blue().bold()); // 目录名使用蓝色加粗
        } else {
            // 使用统一的颜色输出
            print_file_color(entry, &file_name_str);
        }
    }
}

// 输出文件的详细信息
fn print_long_format(metadata: &Metadata, file_name: &str) {
    // 获取文件类型（目录或普通文件）
    let file_type = if metadata.is_dir() { "d" } else { "-" };
    let is_dir = metadata.is_dir();

    // 获取文件大小
    let file_size = metadata.len(); // 这里是文件大小，使用 `len` 方法
    let modified_time = match metadata.modified() {
        Ok(time) => format_system_time(time),
        Err(_) => String::from("未知时间"),
    };

    // 判断文件名是否是隐藏文件
    let is_hidden = file_name.starts_with('.');
    // 判断文件是否是可执行文件
    let is_executable = metadata.permissions().readonly() == false &&
        metadata.file_type().is_file() &&
        file_name.ends_with(".exe");
    // 是否压缩文件 zip, tar, gz, bz2, rar, 7z, tgz, txz
    let is_compressed = file_name.ends_with(".zip") ||
        file_name.ends_with(".tar") ||
        file_name.ends_with(".gz") ||
        file_name.ends_with(".bz2") ||
        file_name.ends_with(".rar") ||
        file_name.ends_with(".7z") ||
        file_name.ends_with(".tgz") ||
        file_name.ends_with(".txz");

    // 美化输出格式：文件类型、大小、时间、文件名，不同类型使用不同颜色
    let formatted_output = format!(
        "{} {:>10} {} {}",
        file_type,
        file_size,
        modified_time,
        file_name_color(file_name, is_dir, is_hidden, is_executable, is_compressed)
    );

    println!("{}", formatted_output);
}

// 根据文件类型返回文件名的颜色
fn file_name_color(file_name: &str,
                   is_dir: bool,
                   is_hidden: bool,
                   is_executable: bool,
                   is_compressed: bool) -> String {
    if is_dir {
        file_name.blue().bold().to_string() // 目录用蓝色加粗显示
    } else if is_hidden {
        file_name.yellow().to_string() // 隐藏文件用黄色显示
    } else if is_executable {
        file_name.green().to_string() // 可执行文件用绿色显示
    } else if is_compressed {
        file_name.cyan().to_string() // 压缩文件用青色显示
    } else {
        file_name.to_string() // 其他文件默认显示
    }
}

// 输出文件颜色，简短形式
fn print_file_color(entry: &DirEntry, file_name: &str) {
    if let Ok(file_type) = entry.file_type() { // 处理 Result
        if file_type.is_dir() {
            println!("{}", file_name.blue().bold()); // 目录用蓝色加粗显示
        } else {
            let is_dir = file_type.is_dir();
            let is_hidden = file_name.starts_with('.');
            let is_executable = entry.metadata().map_or(false, |m|
                m.permissions().readonly() == false &&
                    m.file_type().is_file() &&
                    file_name.ends_with(".exe"),
            );
            let is_compressed = file_name.ends_with(".zip") ||
                file_name.ends_with(".tar") ||
                file_name.ends_with(".gz") ||
                file_name.ends_with(".bz2") ||
                file_name.ends_with(".rar") ||
                file_name.ends_with(".7z") ||
                file_name.ends_with(".tgz") ||
                file_name.ends_with(".txz");

            println!("{}", file_name_color(file_name, is_dir, is_hidden, is_executable, is_compressed));
        }
    } else {
        eprintln!("无法获取 {} 的文件类型", file_name);
    }
}

// 将文件名称做颜色格式化
/*fn format_file_name(file_name: &str) -> String {
    if file_name.starts_with('.') {
        file_name.yellow().to_string() // 隐藏文件用黄色显示
    } else {
        file_name.to_string()
    }
}*/

// 将系统时间格式化为可读的字符串
fn format_system_time(system_time: SystemTime) -> String {
    let datetime = system_time
        .duration_since(UNIX_EPOCH)
        .unwrap_or_default()
        .as_secs();
    // 使用 NaiveDateTime::from_timestamp 将时间戳转换为日期时间
    let naive_datetime = DateTime::from_timestamp(datetime as i64, 0).unwrap().time();
    format!("{}", naive_datetime.format("%Y-%m-%d %H:%M:%S"))
}
